//
//  TableViewController.swift
//  DemoProject
//
//  Created by hao on 2018/7/18.
//  Copyright © 2018年 hao. All rights reserved.
//
/// RxSwift tableview 和 collectionView 范例: http://www.hangge.com/blog/cache/category_72_4.html

import UIKit
import RxDataSources

// RxSwift 并未进一步封装代理数据源协议，需自己实现  tableView.rx.setDelegate(self).disposed(by: disposeBag)

class TableViewController: BaseTableViewController {

    lazy var testTableView: UITableView = {
        let _table = UITableView(frame: self.view.bounds, style: .plain)
        self.tableHeadView.addSubview(_table)
//        self.tableHeadView.size = _table.size
        let footview = UIView()
        footview.backgroundColor = kColorWithRGB(220, 220, 220)
        footview.frame = CGRect(x: 0, y: 0, width: _table.width, height: 15)
        _table.tableFooterView = footview
        return _table
    }()
    
    var isEdit = true
    
    let disposeBag = DisposeBag()
    let cellDemoIdentifier = "UITableViewCellDemoIdentifier"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupData()
        _rxProperty()
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "编辑", style: .done, target: self, action: #selector(edit))
    }
    
    @objc private func edit() {
        // 进入编辑模式
        testTableView.setEditing(isEdit, animated: true)
        isEdit = !isEdit
    }
    
    private func _rxProperty() {
        var textArr  = ["RxDataSources简单使用",
                        "刷新表格数据",
                        "表格数据的搜索过滤",
                        "可编辑表格",
                        "不同类型的单元格"
                        ]
        
        let targetController = [TestRxDataSourcesController.self,
                                TestRxReloadController.self,
                                TestRxTableSearchController.self,
                                RxCURDTableController.self,
                                RxTestCellDifferController.self,
                                ]
        
        tableHeadView.height = CGFloat(textArr.count*44)+15
        testTableView.height = tableHeadView.height
        testTableView.register(UITableViewCell.self, forCellReuseIdentifier: cellDemoIdentifier)
        let items = Observable.just(textArr)
        
        // 绑定数据源
        items.bind(to: testTableView.rx.items) { [weak self] (tableView, row, item) -> UITableViewCell in
            let cell = tableView.dequeueReusableCell(withIdentifier: self!.cellDemoIdentifier)!
            cell.textLabel?.text = "\(row): \(item)"
            cell.accessoryType = .detailButton
            return cell
            }.disposed(by: disposeBag)
        
        // 获取选中项的索引
        testTableView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath in
            //            if let cell = self?.testTableView.cellForRow(at: indexPath) {
            //
            //            }
            self?.testTableView.deselectRow(at: indexPath, animated: true)
            let controller = targetController[indexPath.row].init()
            controller.navigationItem.title = textArr[indexPath.row]
            self?.navigationController?.pushViewController(controller, animated: true)
            print(info: "选中项的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        // 获取选中项的内容
        testTableView.rx.modelSelected(String.self).subscribe(onNext: { item in
            print(info: "选中项的标题为：\(item)")
        }).disposed(by: disposeBag)
        
        // 同时获取选中项和内容
        Observable.zip(testTableView.rx.itemSelected, testTableView.rx.modelSelected(String.self))
            .bind { indexPath, item in
                print(info: "选中项的indexPath为：\(indexPath)")
                print(info: "选中项的标题为：\(item)")
            }
            .disposed(by: disposeBag)
        
        // 获取点击的尾部图标的索引
        testTableView.rx.itemAccessoryButtonTapped.subscribe(onNext: { indexPath in
            print(info: "尾部项的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        Observable<Int>.timer(3, scheduler: MainScheduler.instance).subscribe(onNext: { [weak self] _ in
            textArr[0] = "修改后的值"
            self?.tableView.reloadData()
            print(info: textArr)
        }).disposed(by: disposeBag)
    }
    
    private func setupData() {
        let titles = ["设置行、headview、footview高度",
                      "separatorStyle",
                      "separatorColor",
                      "separatorInset",
                      "contentInset",
                      "tableView 编辑操作",
                      "tableView附件的相关方法"]
        
        let descArr = [
                       """
                        属性设置
                        设置表示图的行高(默认为44)
                        CGFloat rowHeight;

                        设置分组样式时的头视图高度和尾视图高度(当代理方法没有实现时才有效)
                        CGFloat sectionHeaderHeight;
                        CGFloat sectionFooterHeight;

                        设置一个行高的估计值(默认为0，表示没有估计,7.0之后可用)
                        CGFloat estimatedRowHeight;
                        注意：这个属性官方的解释是如果你的tableView的行高是可变的，那么设计一个估计高度可以加快代码的运行效率。
                        下面这两个属性和上面相似，分别设置分区头视图和尾视图的估计高度(7.0之后可用)
                        CGFloat estimatedSectionHeaderHeight;
                        CGFloat estimatedSectionFooterHeight;
                       """,
                       "分隔线样式",
                       "分隔线颜色",
                       "分隔线缩近(可用来设置分隔线宽度)",
                       "增加tableview滚动区域",
                       """
                        设置是否是编辑状态(编辑状态下的cell左边会出现一个减号，点击右边会划出删除按钮)
                        @property (nonatomic, getter=isEditing) BOOL editing;
                        - (void)setEditing:(BOOL)editing animated:(BOOL)animated;

                        设置cell是否可以被选中(默认为YES)
                        @property (nonatomic) BOOL allowsSelection;

                        设置cell编辑模式下是否可以被选中
                        @property (nonatomic) BOOL allowsSelectionDuringEditing;

                        设置是否支持多选
                        @property (nonatomic) BOOL allowsMultipleSelection;

                        设置编辑模式下是否支持多选
                        @property (nonatomic) BOOL allowsMultipleSelectionDuringEditing;
                       """,
                       """
                        设置索引栏最小显示行数
                        @property (nonatomic) NSInteger sectionIndexMinimumDisplayRowCount;
                        设置索引栏字体颜色
                        @property (nonatomic, retain) UIColor *sectionIndexColor;

                        设置索引栏背景颜色
                        @property (nonatomic, retain) UIColor *sectionIndexBackgroundColor;

                        设置索引栏被选中时的颜色
                        @property (nonatomic, retain) UIColor *sectionIndexTrackingBackgroundColor;
                       """]
        
        addTitles(titles, footDescs: descArr)
    }
    
}

fileprivate extension BaseViewController {
    
    fileprivate func createTableView() -> UITableView {
        let tableView = UITableView(frame: self.view.bounds, style: .plain)
        self.view.addSubview(tableView)
        tableView.top = kStatusBarAndNaviHeight()
        tableView.height = self.view.height-tableView.top
        return tableView
    }
    
    //获取随机数据
    fileprivate func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
        print(info: "正在请求数据......")
        let items = (0 ..< 5).map { _ in
            Int(arc4random())
        }
        let observable = Observable.just([SectionModel(model: "S", items: items)])
        return observable.delay(2, scheduler: MainScheduler.instance)
    }
    
}

// MARK: RxDataSources简单使用
fileprivate class TestRxDataSourcesController: BaseViewController {
    
    lazy var tableView: UITableView = {
        return self.createTableView()
    }()
    
    let identifier = "TestRxDataSourcesCellIdentifier"
    
    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: identifier)
//        _useOwnSectionDemo()
        _customSectionAnd()
    }
    
    // 使用自带的Section
    private func _useOwnSectionDemo() {
        let items = Observable.just([SectionModel(model: "SectionModel头部",
                                                  items: ["UILable的用法",
                                                          "UIText的用法",
                                                          "UIButton的用法"])])
        let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, String>>(configureCell:  { (dataSource, tableView, indexPath, item) -> UITableViewCell in
            let cell = tableView.dequeueReusableCell(withIdentifier: "TestRxDataSourcesCellIdentifier")!
            cell.textLabel?.text = "\(indexPath.row): \(item)"
            return cell
        })
        
        // 绑定单元格数据
        items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
    }
    
    private func _customSectionAnd() {
        //初始化数据
        let sections = Observable.just([
            TestRxDataSourcesSection(header: "基本控件", items: [
                "UILable的用法",
                "UIText的用法",
                "UIButton的用法"
                ]),
            TestRxDataSourcesSection(header: "高级控件", items: [
                "UITableView的用法",
                "UICollectionViews的用法"
                ])
            ])
        
        //创建数据源
        let dataSource = RxTableViewSectionedAnimatedDataSource<TestRxDataSourcesSection>(
            //设置单元格
            configureCell: { ds, tv, ip, item in
                let cell = tv.dequeueReusableCell(withIdentifier: "TestRxDataSourcesCellIdentifier")
                    ?? UITableViewCell(style: .default, reuseIdentifier: "TestRxDataSourcesCellIdentifier")
                cell.textLabel?.text = "\(ip.row)：\(item)"
                return cell
            },
            //设置分区头标题
            titleForHeaderInSection: { ds, index in
                return ds.sectionModels[index].header
            }
        )
        
        //绑定单元格数据
        sections.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
    }
    
}

// MARK: 自定义SectionModel
fileprivate struct TestRxDataSourcesSection {
    var header: String
    var items: [Item]
}
extension TestRxDataSourcesSection: AnimatableSectionModelType {
    
    typealias Item = String
    
    var identity: String {
        return header
    }

    init(original: TestRxDataSourcesSection, items: [Item]) {
        self = original
        self.items = items
    }
}

// MARK: 刷新表格数据 (返回上一级不释放，不知道哪里循环引用了) 问题在 flatMapLatest 中，[weak self]即可
fileprivate class TestRxReloadController: BaseViewController {
    
    lazy var tableView: UITableView = {
        return self.createTableView()
    }()
    
    let disposeBag = DisposeBag()
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        let button = UIBarButtonItem()
        button.title = "刷新"
        let stop = UIBarButtonItem()
        stop.title = "停止"
        self.navigationItem.rightBarButtonItems = [button, stop]
        // 可以通过 throttle 设置个阀值（比如 1 秒），如果在1秒内有多次点击则只取最后一次
        // throttle、flatMapLatest、flatMapFirst三个操作符使用一个即可防止表格多次刷新
        // 不加‘停止’的写法
//        let randomResult = button.rx.tap.asObservable()
//                .throttle(1, scheduler: MainScheduler.instance) // 在主线程中操作，1秒内值若多次改变，取最后一次
//                .startWith(()) // 加这个为了让一开始就能自动请求一次数据
//                .flatMapLatest(getRandomResult) // 连续请求时只取最后一次数据  // 或者 flatMapFirst: 连续请求时只取第一次数据
//                .share(replay: 1)
        
        // 加上'停止'的写法
        let randomResult = button.rx.tap.asObservable()
            .startWith(()) // 加这个为了让一开始就能自动请求一次数据
            .flatMapLatest { [weak self] _ -> Observable<[SectionModel<String, Int>]> in // 连续请求时只取最后一次数据  // 或者 flatMapFirst: 连续请求时只取第一次数据
                // takeUntil 操作符可以监视另外一个 Observable， 即 notifier
                // 如果 notifier 发出值或 complete 通知，那么源 Observable 便自动完成，停止发送事件
                self!.getRandomResult().takeUntil(stop.rx.tap)
            }.share(replay: 1)
        
        
        //创建数据源
        let dataSource = RxTableViewSectionedReloadDataSource
            <SectionModel<String, Int>>(configureCell: {
                (dataSource, tv, indexPath, element) in
                let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
                cell.textLabel?.text = "条目\(indexPath.row)：\(element)"
                return cell
            })
        
        // 绑定单元格数据
        randomResult
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
        
    }
    
}

// MARK: 表格数据的搜索过滤
fileprivate class TestRxTableSearchController: BaseViewController {

    lazy var tableView: UITableView = {
        return self.createTableView()
    }()
    
    let searchBar = UISearchBar()
    
    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        let button = UIBarButtonItem()
        button.title = "刷新"
        self.navigationItem.rightBarButtonItem = button
        searchBar.frame = CGRect(x: 0, y: 0, width: tableView.width, height: 44)
        tableView.tableHeaderView = searchBar
        
        //随机的表格数据
        /**
         可以这么写，但是会出现循环引用释放不了
         .flatMapLatest(getRandomResult) //获取数据
         .flatMap(filterResult) //筛选数据  */
        let randomResult = button.rx.tap.asObservable()
            .startWith(()) //加这个为了让一开始就能自动请求一次数据
            .flatMapLatest({ [weak self] _ -> Observable<[SectionModel<String, Int>]> in
                self!.getRandomResult()
            }) //获取数据
            .flatMap({ [weak self] (items) -> Observable<[SectionModel<String, Int>]> in
                self!.filterResult(data: items)
            }) // 筛选数据
            .share(replay: 1)
        
        //创建数据源
        let dataSource = RxTableViewSectionedReloadDataSource
            <SectionModel<String, Int>>(configureCell: {
                (dataSource, tv, indexPath, element) in
                let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
                cell.textLabel?.text = "条目\(indexPath.row)：\(element)"
                return cell
            })
        
        //绑定单元格数据
        randomResult
            .bind(to: tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
    
    //过滤数据
    private func filterResult(data:[SectionModel<String, Int>]) -> Observable<[SectionModel<String, Int>]> {
        return self.searchBar.rx.text.orEmpty
            //.debounce(0.5, scheduler: MainScheduler.instance) //只有间隔超过0.5秒才发送
            .flatMapLatest {
                query -> Observable<[SectionModel<String, Int>]> in
                print(info: "正在筛选数据（条件为：\(query)）")
                //输入条件为空，则直接返回原始数据
                if query.isEmpty {
                    return Observable.just(data)
                }
                    //输入条件为不空，则只返回包含有该文字的数据
                else {
                    var newData:[SectionModel<String, Int>] = []
                    for sectionModel in data {
                        let items = sectionModel.items.filter{ "\($0)".contains(query) }
                        newData.append(SectionModel(model: sectionModel.model, items: items))
                    }
                    return Observable.just(newData)
                }
        }
    }

}




